package com.ape.mapsa.common;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.faces.application.ConfigurableNavigationHandler;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.ComponentSystemEvent;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.primefaces.context.RequestContext;
import org.springframework.dao.DataAccessException;

import com.ape.mapsa.model.Session;
import com.ape.mapsa.model.User;
import com.ape.mapsa.model.UserRole;
import com.ape.mapsa.service.IUserService;

@ManagedBean(name = "userMB")
@SessionScoped
public class UserBean {
	public static final String SUCCESS = "success";
	public static final String LOGGED_OUT = "logged_out";
	public static final String ERROR = "error";

	// Spring User Service is injected...
	@ManagedProperty(value = "#{UserService}")
	IUserService userService;

	@ManagedProperty(value = "#{homeMenuMB}")
	private UserHomeMenuBean homeBean;

	private static final Logger logger = Logger.getLogger(UserBean.class);

	private String email;
	private String firstName;
	private String lastName;
	private String userName;
	private String password;
	private HttpSession currentSession;

	private boolean loggedIn;
	private List<UserRole> roles;

	private String currentIpAddress;
	private Long userId;

	public UserBean() {
		super();
		HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
		if (session != null) {
			session.invalidate();
		}
	}

	public boolean isLoggedIn() {
		return loggedIn;
	}

	public void checkLogin(ComponentSystemEvent event) {
		logger.info("check login");
		UIViewRoot source = (UIViewRoot) event.getSource();
		FacesContext context = FacesContext.getCurrentInstance();
		HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
		HttpSession session = request.getSession(false);
		if (session != null && System.currentTimeMillis() - session.getLastAccessedTime() > 30 * 60 * 1000) {
			logger.info("Session timed out!!");
			context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"Es posible que su sesión haya terminado por falta de actividad y debe volver a conectarse.", null));
			logout();
		}
		String ipAddress = request.getHeader("X-FORWARDED-FOR");
		if (ipAddress == null) {
			ipAddress = request.getRemoteAddr();
		}
		if (currentIpAddress != null && !currentIpAddress.equals(ipAddress)) {
			logout();
		}

		if (!source.getViewId().contains("login") && !isLoggedIn()) {
			ConfigurableNavigationHandler handler = (ConfigurableNavigationHandler) context.getApplication().getNavigationHandler();
			handler.handleNavigation(context, "*", "login?faces-redirect=true");
		} else if (source.getViewId().contains("login") && isLoggedIn()) {
			ConfigurableNavigationHandler handler = (ConfigurableNavigationHandler) context.getApplication().getNavigationHandler();
			handler.performNavigation("welcome");
		}
	}

	public String login() {

		String message = "Compruebe usuario y contraseña.";
		try {
			HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
			User userByEmail = userService.getUserByEmail(getEmail());
			if (userByEmail != null && userByEmail.getActive() == 1) {
				// Login via the Servlet Context
				request.login(getEmail(), getPassword());
			} else {
				if (userByEmail == null) {
					message = "Error al iniciar session el usuario no existe.";
				} else if (userByEmail != null && userByEmail.getActive() == 1) {
					message = "Error al iniciar session verifique su contraseña";
				} else if (userByEmail != null && userByEmail.getActive() == 0) {
					message = "Error al iniciar session. el usuario esta inactivo.";
				}
				throw new ServletException(message);
			}
			// Display a message based on the User role
			User user = userByEmail;

			userId = userByEmail.getId();
			firstName = userByEmail.getFirstName();
			loggedIn = true;
			roles = new ArrayList<UserRole>();
			for (UserRole role : user.getRoles()) {
				roles.add(role);
			}
			logger.info(message);
			currentSession = request.getSession();
			request.getSession().setAttribute("email", email);
			currentIpAddress = request.getHeader("X-FORWARDED-FOR");
			if (currentIpAddress == null) {
				currentIpAddress = request.getRemoteAddr();
			}

			Session session = new Session();
			session.setUser(user);
			session.setIpAddress(currentIpAddress);
			session.setSessionStart(new Date());
			session.setSessionId(currentSession.getId());
			userService.addSession(session);

			homeBean.initilizeMenu();
			RequestContext.getCurrentInstance().update("inboxMenuForm:inboxMenuBar");

			return SUCCESS;
		} catch (ServletException e) {
			loggedIn = false;
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error al iniciar session: ", message));
		}
		return ERROR;
	}

	/**
	 * Add User
	 * 
	 * @return String - Response Message
	 */
	public String addUser() {
		try {
			User user = new User();
			user.setEmail(getEmail());
			user.setFirstName(getFirstName());
			user.setLastName(getLastName());
			user.setUserName(getUserName());
			user.setPassword(getPassword());
			getUserService().addUser(user);
			return SUCCESS;
		} catch (DataAccessException e) {
			e.printStackTrace();
		}

		return ERROR;
	}

	public String logout() {
		HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
		if (session != null) {
			if (session.getId().equals(currentSession.getId())) {
				logger.info("Same session logging out");
				Session userActiveSession = userService.getSessionById(session.getId());
				userActiveSession.setSessionEnd(new Date());
				userService.updateSession(userActiveSession);
			}
			session.invalidate();

		}
		loggedIn = false;
		return LOGGED_OUT;
	}

	/**
	 * Reset Fields
	 * 
	 */
	public void reset() {
		this.setEmail("");
		this.setFirstName("");
		this.setLastName("");
		this.setUserName("");
		this.setPassword("");
	}

	/**
	 * Get User Service
	 * 
	 * @return IUserService - User Service
	 */
	public IUserService getUserService() {
		return userService;
	}

	/**
	 * Set User Service
	 * 
	 * @param IUserService
	 *            - User Service
	 */
	public void setUserService(IUserService userService) {
		this.userService = userService;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public String toString() {
		return userName;
	}

	public List<UserRole> getRoles() {
		return roles;
	}

	public void setRoles(List<UserRole> roles) {
		this.roles = roles;
	}

	public UserHomeMenuBean getHomeBean() {
		return homeBean;
	}

	public void setHomeBean(UserHomeMenuBean homeBean) {
		this.homeBean = homeBean;
	}

	public HttpSession getCurrentSession() {
		return currentSession;
	}

	public void setCurrentSession(HttpSession currentSession) {
		this.currentSession = currentSession;
	}

	public String getCurrentIpAddress() {
		return currentIpAddress;
	}

	public void setCurrentIpAddress(String currentIpAddress) {
		this.currentIpAddress = currentIpAddress;
	}

	public Long getUserId() {
		return userId;
	}

	public void setUserId(Long userId) {
		this.userId = userId;
	}

	public void setLoggedIn(boolean loggedIn) {
		this.loggedIn = loggedIn;
	}

}
